package cn.lingyangwl.agile.infra.datamanage.service.impl;

import cn.lingyangwl.agile.infra.datamanage.assembly.*;
import cn.lingyangwl.agile.infra.datamanage.db.*;
import cn.lingyangwl.agile.infra.datamanage.mapper.*;
import cn.lingyangwl.agile.infra.datamanage.mode.entity.*;
import cn.lingyangwl.agile.infra.datamanage.mode.rqrs.*;
import cn.lingyangwl.agile.infra.datamanage.service.*;
import cn.lingyangwl.agile.infra.gen.manager.*;
import cn.lingyangwl.agile.infra.gen.model.entity.*;
import cn.lingyangwl.agile.infra.module.datamanage.db.*;
import cn.lingyangwl.framework.data.mate.annotations.*;
import cn.lingyangwl.framework.mybatis.plus.utils.*;
import cn.lingyangwl.framework.tool.core.exception.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author shenguangyang
 */
@Service
@RequiredArgsConstructor
public class DatasourceServiceImpl extends ServiceImpl<DatasourceConfigMapper, DatasourceConfig>
    implements DatasourceService {
    private final GenTableIndexManager genTableIndexManager;
    private final GenTableColumnManager genTableColumnManager;
    private final GenTableManager genTableManager;
    private final DatasourceConfigAssembly datasourceConfigAssembly;

    @Override
    public List<DatasourceResp> listAll() {
        LambdaQueryWrapper<DatasourceConfig> queryWrapper = Wrappers.<DatasourceConfig>lambdaQuery()
                .orderByDesc(DatasourceConfig::getUpdatedAt);
        List<DatasourceConfig> list = this.list(queryWrapper);
        return list.stream().map(datasourceConfigAssembly::toResp).collect(Collectors.toList());
    }


    @Override
    public void update(DatasourceConfig datasourceConfig) {
        if (!this.updateById(datasourceConfig)) {
            throw new BizException("更新失败");
        }
    }

    @Override
    @Transactional
    public void delete(DatasourceConfig datasourceConfig) {
        List<GenTable> genTableList = genTableManager.listByDatasourceId(datasourceConfig.getId());
        if (!genTableList.isEmpty()) {
            List<Long> tableIds = genTableList.stream().map(GenTable::getId).collect(Collectors.toList());
            genTableManager.removeByIds(tableIds);
            genTableIndexManager.deleteBatchByTableIds(tableIds);
            genTableColumnManager.deleteBatchByTableIds(tableIds);
        }
        if (!this.removeById(datasourceConfig)) {
            throw new BizException("删除失败");
        }
    }

    @Override
    @FieldBindHandle
    public IPage<DatasourceConfig> page(DatasourceConfigQuery req) {
        LambdaQueryWrapper<DatasourceConfig> queryWrapper = Wrappers.<DatasourceConfig>lambdaQuery()
                .eq(Objects.nonNull(req.getDbType()), DatasourceConfig::getDbType, req.getDbType())
                .like(cn.lingyangwl.framework.tool.core.StringUtils.isNotEmpty(req.getName()), DatasourceConfig::getName, req.getName())
                .orderByDesc(DatasourceConfig::getUpdatedAt);
        return this.page(PageUtil.to(req), queryWrapper);
    }

    @Override
    public List<TableDefinition> listTable(DbTableReq rq) {
        DatasourceConfig dataSourceConfig = this.getById(rq.getDatasourceId());
        GeneratorConfig generatorConfig = GeneratorConfig.build(dataSourceConfig);
        SQLService service = SQLServiceFactory.build(generatorConfig);
        // 筛选表
        if (StringUtils.isNotEmpty(rq.getTableName())) {
            Pattern pattern = Pattern.compile(".*" + rq.getTableName() + ".*");
            return service.getTableSelector(generatorConfig).getSimpleTableDefinitions()
                    .stream().filter(x -> pattern.matcher(x.getTableName()).matches()).collect(Collectors.toList());
        } else {
            return service.getTableSelector(generatorConfig).getSimpleTableDefinitions();
        }
    }

    @Override
    public void deleteBatchByIds(List<Long> ids) {
        this.removeByIds(ids);
    }

    /**
     * 返回SQL上下文列表
     *
     * @param tableNames 表名
     * @param generatorConfig 配置
     * @return 返回SQL上下文
     */
    private List<SQLContext> buildSQLContextList(List<String> tableNames, GeneratorConfig generatorConfig) {
        List<SQLContext> contextList = new ArrayList<>();
        SQLService service = SQLServiceFactory.build(generatorConfig);

        TableSelector tableSelector = service.getTableSelector(generatorConfig);
        tableSelector.setSchTableNames(tableNames);

        List<TableDefinition> tableDefinitions = tableSelector.getTableDefinitions();

        for (TableDefinition tableDefinition : tableDefinitions) {
            SQLContext sqlContext = new SQLContext(tableDefinition);
            sqlContext.setDbName(generatorConfig.getDbName());
            contextList.add(sqlContext);
        }
        return contextList;
    }

    @Override
    public List<SQLContext> listSqlContext(Long datasourceId, List<String> tableNames) {
        if (CollectionUtils.isEmpty(tableNames)) {
            return new ArrayList<>();
        }
        DatasourceConfig datasourceConfig = this.getById(datasourceId);
        Assert.notNull(datasourceConfig, "数据源不存在");
        GeneratorConfig generatorConfig = datasourceConfigAssembly.toEntity(datasourceConfig);
        return this.buildSQLContextList(tableNames, generatorConfig);
    }
}
